/*
This file is part of Hikari, a library that allows developers
to use Flash in their Ogre3D applications.

Copyright (C) 2008 Adam J. Simmons

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
//Edited to adapt to new interface
#ifndef _EVENT_HANDLER_H_
#define _EVENT_HANDLER_H_

#import "PROGID:ShockwaveFlash.ShockwaveFlash" named_guids
#include <sstream>
#include "SwfUI.h"
#include "FlashCall.h"

namespace SwfUI {
	namespace detail {

		class EventHandler : public ShockwaveFlashObjects::_IShockwaveFlashEvents
		{
		public:	
			LPCONNECTIONPOINT connectionPoint;	
			DWORD cookie;
			Control* control;
			int refCount;

		public:
			EventHandler() : cookie(0), connectionPoint(0), refCount(0)
			{
			}

			virtual ~EventHandler()
			{
			}

			HRESULT Init(Control* control)
			{
				this->control = control;
				HRESULT result = NOERROR;
				LPCONNECTIONPOINTCONTAINER cPointContainer = 0;

				if ((control->flashObject->QueryInterface(IID_IConnectionPointContainer, (void**)&cPointContainer) == S_OK) &&
					(cPointContainer->FindConnectionPoint(__uuidof(ShockwaveFlashObjects::_IShockwaveFlashEvents), &connectionPoint) == S_OK))			
				{
					result = connectionPoint->Advise(this, &cookie);
				}

				if(cPointContainer)
					cPointContainer->Release();

				return result;
			}

			HRESULT Shutdown()
			{
				HRESULT result = S_OK;

				if(connectionPoint)
				{
					if(cookie)
					{
						result = connectionPoint->Unadvise(cookie);
						cookie = 0;
					}

					connectionPoint->Release();
					connectionPoint = 0;
				}

				return result;
			}

			HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppv)
			{
				*ppv = 0;

				if (riid == IID_IUnknown)
				{
					*ppv = (LPUNKNOWN)this;
					AddRef();
					return S_OK;
				}
				else if (riid == IID_IDispatch)
				{
					*ppv = (IDispatch*)this;
					AddRef();
					return S_OK;
				}
				else if (riid == __uuidof(ShockwaveFlashObjects::_IShockwaveFlashEvents))
				{
					*ppv = (ShockwaveFlashObjects::_IShockwaveFlashEvents*) this;
					AddRef();
					return S_OK;
				}
				else
				{   
					return E_NOTIMPL;
				}
			}

			ULONG STDMETHODCALLTYPE AddRef()
			{  
				return ++refCount;
			}

			ULONG STDMETHODCALLTYPE Release()
			{
				--refCount;

				if(!refCount)
				{
					delete this;
					return 0;
				}

				return refCount;
			}

			virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo)
			{
				return E_NOTIMPL;
			}

			virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
			{
				return E_NOTIMPL; 
			}

			virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid,DISPID* rgDispId)
			{
				return E_NOTIMPL; 
			}

			virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
				WORD wFlags, ::DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult,
				::EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr)
			{
				switch(dispIdMember)
				{
				case 0x7a6:
					break;
				case 0x96:			
					if((pDispParams->cArgs == 2) && (pDispParams->rgvarg[0].vt == VT_BSTR) && (pDispParams->rgvarg[1].vt == VT_BSTR))
						FSCommand(pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0].bstrVal);
					break;
				case 0xC5:
					if((pDispParams->cArgs == 1) && (pDispParams->rgvarg[0].vt == VT_BSTR))
						FlashCall(pDispParams->rgvarg[0].bstrVal);
					break;
				case DISPID_READYSTATECHANGE:
					break;
				default:
					return DISP_E_MEMBERNOTFOUND;
				} 
				
				return S_OK;
			}

			HRESULT STDMETHODCALLTYPE OnReadyStateChange (long newState)
			{	
				return S_OK;
			}

			HRESULT STDMETHODCALLTYPE OnProgress(long percentDone )
			{		
				return S_OK;
			}

			HRESULT STDMETHODCALLTYPE FSCommand (_bstr_t command, _bstr_t args)
			{
				control->onFSCommand(command, args);
				return S_OK;
			}	

			HRESULT STDMETHODCALLTYPE FlashCall (_bstr_t request)
			{
				ArgumentList args;
				std::wstring functionName;
				if(detail::deserializeInvocation((wchar_t*)request,functionName,args))
				{
					Argument returnValue = control->onFlashCall(functionName,args);
					control->flashObject->SetReturnValue(serializeValue(returnValue).c_str());
				}

				return S_OK;
			}
		};

	}
}

#endif